package me.zhengjie.domain;

import cn.hutool.core.bean.BeanUtil;
import me.zhengjie.dto.*;
import me.zhengjie.dto.sqlServer.Pallet;
import me.zhengjie.dto.sqlServer.Processcard;
import me.zhengjie.repository.PalletRepository;
import me.zhengjie.repository.PlcUnbindingRepository;
import me.zhengjie.repository.ProcesscardRepository;
import org.springframework.stereotype.Component;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class SseService {

    private static final Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
    private final Thread worker = new Thread(task(), "拆解信息定时推送");
    private final Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create();

    private final PlcUnbindingRepository plcUnbindingRepository;
    private final ProcesscardRepository processcardRepository;
    private final PalletRepository palletRepository;

    public SseService(PlcUnbindingRepository plcUnbindingRepository,ProcesscardRepository processcardRepository,PalletRepository palletRepository){
        this.plcUnbindingRepository=plcUnbindingRepository;
        this.processcardRepository=processcardRepository;
        this.palletRepository=palletRepository;
        this.worker.setDaemon(true);
        this.worker.start();
    }

    public SseEmitter connect(String clientId) {
        SseEmitter sseEmitter = new SseEmitter(3600_000L);

        sseEmitter.onCompletion(() -> {
            log.info("结束连接：{}", clientId);
            sseEmitterMap.remove(clientId);
        });

        sseEmitter.onError(throwable -> {
            log.info("连接异常：{}", clientId);
            sseEmitterMap.remove(clientId);
        });

        sseEmitter.onTimeout(() -> {
            log.info("连接超时：{}", clientId);
            sseEmitterMap.remove(clientId);
        });

        sseEmitterMap.put(clientId, sseEmitter);
        log.info("创建新的sse连接，当前用户：{}", clientId);

        return sseEmitter;
    }

    public SseEmitter errorInfoConnect(String clientId) {
        SseEmitter sseEmitter = new SseEmitter(3600_000L);

        sseEmitter.onCompletion(() -> {
            log.info("结束连接：{}", clientId);
            sseEmitterMap.remove(clientId);
        });

        sseEmitter.onError(throwable -> {
            log.info("连接异常：{}", clientId);
            sseEmitterMap.remove(clientId);
        });

        sseEmitter.onTimeout(() -> {
            log.info("连接超时：{}", clientId);
            sseEmitterMap.remove(clientId);
        });

        sseEmitterMap.put(clientId, sseEmitter);
        log.info("创建新的sse连接，当前用户：{}", clientId);

        return sseEmitter;
    }

    private Runnable task(){
        return () -> {
            while (!this.worker.isInterrupted()) {
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    log.info("定时线程中断");
                    break;
                }
                try {

                    List<String> palletCodes = plcUnbindingRepository.searchContent();
                    Map<String, UnbindingInfo> processcardMap = new HashMap<>();

                    palletCodes.forEach(x ->{
                        Pallet pallet = palletRepository.findPalletByPalletCode(x);
                        Processcard processcard = processcardRepository.findProcesscardById(pallet.getProcesscardId());
                        UnbindingInfo unbindingInfo = new UnbindingInfo();
                        BeanUtil.copyProperties(processcard,unbindingInfo);
                        unbindingInfo.setPalletCode(x);
                        String unbindingStationName = plcUnbindingRepository.findPlcUnbindingByContent(x).getUnbindingStation();
                        processcardMap.put(unbindingStationName,unbindingInfo);
                    });

                    Resp resp = Resp.builder()
                            .msg("成功")
                            .status(200)
                            .data("inventory",processcardMap)
                            .build();

                    String json = this.gson.toJson(resp);
                    log.info("推送信息：{}", json);
                    broadcast(json);

                } catch (Exception e) {
                    Resp resp = Resp.builder()
                                    .msg("没有查询到物料信息")
                                    .status(500)
                                    .build();

                    String json = this.gson.toJson(resp);
                    log.info("推送信息：{}", json);
                    broadcast(json);
                }
            }
        };
    }

    public void sendErrorInfoMessage(ErrorInfoReport errorInfoReport) {
        try {
            Resp resp = Resp.builder()
                    .msg("来自MES的提示信息："+errorInfoReport.getMessage())
                    .status(200)
                    .build();

            String json = this.gson.toJson(resp);
            log.info("mes的提示信息：{}",errorInfoReport.getMessage());
            broadcast(json);

        } catch (Exception e) {
            Resp resp = Resp.builder()
                    .msg("机台报警出错")
                    .status(500)
                    .build();

            String json = this.gson.toJson(resp);
            log.info("机台报警信息：{}", json);
            broadcast(json);
        }
    }

    public void sendStatusChangeMessage(StatusChangeReport statusChangeReport) {
        try {
            Resp resp = Resp.builder()
                    .msg("来自MES的提示信息："+statusChangeReport.getMessage())
                    .status(200)
                    .build();

            String json = this.gson.toJson(resp);
            log.info("mes的提示信息：{}",statusChangeReport.getMessage());
            broadcast(json);

        } catch (Exception e) {
            Resp resp = Resp.builder()
                    .msg("机台报警出错")
                    .status(500)
                    .build();

            String json = this.gson.toJson(resp);
            log.info("机台报警信息：{}", json);
            broadcast(json);
        }
    }

    public void sendGratingAlertsMessage(GratingAlertsReport gratingAlertsReport) {
        try {
            Resp resp = Resp.builder()
                    .msg("来自MES的提示信息："+gratingAlertsReport.getMessage())
                    .status(200)
                    .build();

            String json = this.gson.toJson(resp);
            log.info("mes的提示信息：{}",gratingAlertsReport.getMessage());
            broadcast(json);

        } catch (Exception e) {
            Resp resp = Resp.builder()
                    .msg("机台报警出错")
                    .status(500)
                    .build();

            String json = this.gson.toJson(resp);
            log.info("机台报警信息：{}", json);
            broadcast(json);
        }
    }



    private void broadcast(String json) {
        sseEmitterMap.forEach((k, v) -> {
            try {
                v.send(json, MediaType.APPLICATION_JSON);
            } catch (IOException e) {
                log.error("用户[{}]推送异常:{}", k, e.getMessage());
                sseEmitterMap.remove(k);
            }
        });
    }

}
